<?php
/**
 * FastApp.
 * 10/6/24
 * @Author deepsea159
 * @Contact telegram:deepsea159
 */

namespace App\Game\Api\Service\Platform;

use App\Fastapp\Api\Service\Account\WalletService;
use App\Fastapp\Exception\TipException;
use App\Fastapp\Model\AccountWallet;
use App\Fastapp\Model\AccountWalletLog;
use App\Game\Listener\Event\BetEvent;
use App\Game\Model\Game;
use App\Game\Model\GameAccountRtp;
use App\Game\Model\GameBet;
use App\Game\Model\GamePlatform;
use App\Game\Model\GameSymbol;

class FiverscanService implements GameInterface
{
    const CODE = 'fiverscan';

    const PR = ['PRAGMATIC', 'REELKINGDOM', 'HABANERO', 'BOOONGO', 'PLAYSON', 'CQ9', 'DREAMTECH', 'EVOPLAY', 'TOPTREND', 'PGSOFT', 'GENESIS', 'EVOLUTION', 'EZUGI'];

    public static array $config = [];

    const SYMBOL = ['BRL'];

    public static function syncGameList(): bool
    {
        $res = self::post('provider_list');
        $rtp = self::getConfig()['rtp'];
        $types = [
            'slot' => 2,
            'live' => 1,
        ];
        foreach ($res['providers'] as $provider) {
            $res = self::post('game_list', ['provider_code' => $provider['code']]);
            $in = [];
            $exist = Game::query()->where(['platform' => self::CODE])->pluck('code')->toArray();
            $t = date('Y-m-d H:i:s');
            if (empty($res['games'])) continue;
            foreach ($res['games'] as $item) {
                if (in_array($item['game_code'], $exist)) continue;
                $in[] = [
                    'name' => json_encode([
                        [
                            'lang' => 'all',
                            'text' => $item['game_name']
                        ]
                    ], JSON_UNESCAPED_UNICODE),
                    'code' => $item['game_code'],
                    'platform' => self::CODE,
                    'provider' => strtolower($provider['code']),
                    'rtp' => $rtp,
                    'type' => $types[$provider['type']],
                    'cover' => $item['banner'],
                    'status' => $item['status'],
                    'created_at' => $t,
                    'updated_at' => $t,
                ];
            }
            if ($in) Game::query()->insert($in);
        }
        self::syncSymbol();
        return true;
    }

    public static function syncSymbol(): void
    {
        foreach (self::PR as $provider) {
            $map = ['platform' => self::CODE, 'provider' => strtolower($provider)];
            $game_ids = Game::query()->where($map)->pluck('id')->toArray();
            GameSymbol::query()->whereIn('game_id', $game_ids)->delete();
            $in = [];
            foreach ($game_ids as $gid) {
                foreach (self::SYMBOL as $symbol) {
                    $in[] = [
                        'game_id' => $gid,
                        'symbol' => $symbol
                    ];
                }
            }
            GameSymbol::query()->insert($in);
        }
    }

    public static function gamePlayUrl(array $data): string
    {
        $res = self::post('game_launch', [
            'user_code' => '' . $data['gac_id'],
            'provider_code' => strtoupper($data['provider']),
            'game_code' => $data['code'],
            'lang' => $data['lang'],
        ]);
        if ($res['status']) return $res['launch_url'];
        throw new TipException('game.init_fail');
    }

    public static function createUser(int|string $uid, string $symbol, string $provider = ''): void
    {
        $rtp = GamePlatform::query()->where(['code' => self::CODE])->value('rtp');
        $md = GameAccountRtp::query()->create([
            'code' => self::CODE,
            'user_id' => $uid,
            'rtp' => $rtp,
            'symbol' => $symbol,
            'provider' => strtoupper($provider),
        ]);
        foreach (self::PR as $pr) self::post('control_rtp', ['provider_code' => $pr, 'user_code' => '' . $md->id, 'rtp' => $rtp]);
    }

    public static function killUser(int|string $user_id): bool
    {
        return true;
    }

    public static function setUserRtp(array $data): bool
    {
        foreach (self::PR as $pr) {
            $data['provider_code'] = $pr;
            $res = self::post('control_rtp', $data);
            if ($res['status'] == 1) {
                return false;
            }
        }
        return true;
    }

    public static function getBalance(array $data): array
    {
        if (self::getConfig()['agent_secret'] == $data['agent_secret']) {
            $user_id = GameAccountRtp::query()->where(['id' => $data['user_code']])->value('user_id');
            $res = get_user_cache(['symbol', 'gameid'], $user_id);
            $is_demo = Game::query()->where(['id' => $res['gameid']])->value('demo');
            $wallet = AccountWallet::query()->where(['user_id' => $user_id, 'symbol' => $res['symbol']])->first(['balance', 'balance_demo', 'balance_winnings']);
            return [
                'status' => 1,
                'user_balance' => (float)($is_demo ? bcmul($wallet->balance_demo, '1', 2) : bcmul($wallet->balance, '1', 2))
            ];
        }
        return ['status' => 0, 'msg' => 'INTERNAL_ERROR', 'user_balance' => 0];
    }

    public static function transaction(array $data): array
    {
        if ($data['method'] == 'user_balance') return self::getBalance($data);
        if ($data['method'] == 'transaction') {
            $game_user_id = $data['user_code'];
            $data = $data[$data['game_type']];
            $ga = GameAccountRtp::query()->where(['id' => $game_user_id])->first(['user_id', 'rtp']);
            $res = get_user_cache(['symbol', 'gameid', 'type'], $ga->user_id);
            $bet = (string)$data['bet_money'];
            $payout = (string)$data['win_money'];
            if ($data['txn_type'] == 'credit') {
                $md = GameBet::query()->where(['bet_id' => $data['txn_id']])->first();
                $result_amount = bcsub($md->amount, $payout, 2);
                $md->fill([
                    'result' => $result_amount > 0 ? 3 : 2,
                    'payout' => $payout,
                    'result_amount' => abs($result_amount),
                ])->save();
            } else {
                if (GameBet::query()->where(['bet_id' => $data['txn_id']])->exists()) return ['status' => 0, 'msg' => 'INSUFFICIENT_USER_FUNDS'];
                if ($data['txn_type'] == 'debit') $result_amount = 0; else $result_amount = bcsub($bet, $payout, 2);
                if ($result_amount > 0) $result = 3; else $result = 2;
                $md = GameBet::query()->create([
                    'user_id' => $ga->user_id,
                    'game_id' => $res['gameid'],
                    'bet_id' => $data['txn_id'],
                    'transaction_id' => $data['txn_id'],
                    'platform' => self::CODE,
                    'amount' => $bet,
                    'payout' => $payout,
                    'result_amount' => abs($result_amount),
                    'rtp' => $ga->rtp,
                    'symbol' => $res['symbol'],
                    'result' => $result,
                ]);
            }
            if (!$md) return ['status' => 0, 'msg' => 'INSUFFICIENT_USER_FUNDS'];
            $ord = [
                'user_id' => $ga->user_id,
                'symbol' => $res['symbol'],
                'amount' => $bet,
                'type' => AccountWalletLog::USE_BALANCE,
                'object_type' => AccountWalletLog::OBJ_TYPE_GAME_BAT,
                'object_id' => $md->id,
            ];
            $is_demo = Game::query()->where(['id' => $res['gameid']])->value('demo');
            if ($data['txn_type'] != 'credit') WalletService::dec($ord, null, $is_demo ? 'balance_demo' : 'balance');
            if (in_array($data['txn_type'], ['debit_credit', 'credit'])) {
                $ord['amount'] = $payout;
                $ord['type'] = AccountWalletLog::RECHARGE;
                if (!$is_demo) {
                    $up['status'] = 1;
                    $setting = api_cache()->getAppSetting($res['type']);
                    if ($md->result == 2) {//抽水
                        $up['pump'] = bcmul($md->result_amount, bcdiv($setting['pump_bet'], '100', 4));
                        $ord['amount'] = bcsub($ord['amount'], $up['pump'], 4);
                    } else if ($md->result == 3 && !empty($setting['kill_bet'])) {//杀单
                        $n = redis()->incr('game:bet_n');
                        if ($n > $setting['kill_bet']) {
                            redis()->set('game:bet_n', 0);
                            $up['status'] = 2;
                        }
                    }
                    $md->update($up);
                }
                if (bccomp($ord['amount'], '0', 4) == 1) $wallet = WalletService::inc($ord, null, $is_demo ? 'balance_demo' : 'balance');
            }
            if (empty($wallet)) $wallet = AccountWallet::query()->select(['balance', 'balance_demo'])->where(['user_id' => $ga->user_id, 'symbol' => $res['symbol']])->first();
            if ($data['txn_type'] != 'debit') api_dispatch(new BetEvent($ga->user_id, $md->id, $res['type']));
            return [
                'status' => 1,
                'user_balance' => (float)($is_demo ? bcmul($wallet->balance_demo, '1', 2) : bcmul($wallet->balance, '1', 2))
            ];
        }
        return ['status' => 0, 'msg' => 'INSUFFICIENT_USER_FUNDS'];
    }

    public static function getConfig(bool $refresh = false): array
    {
        if (!self::$config || $refresh) {
            $md = GamePlatform::query()->where(['code' => self::CODE])->first(['config', 'rtp']);
            self::$config = array_column($md->config, 'text', 'field');
            self::$config['rtp'] = $md->rtp;
        }
        return self::$config;
    }

    public static function post(string $method, array $data = []): array
    {
        $config = self::getConfig();
        $data['method'] = $method;
        $data['agent_code'] = $config['agent_code'];
        $data['agent_token'] = $config['agent_token'];
        $curl = curl_init();
        curl_setopt_array($curl, array(
            CURLOPT_URL => $config['url'],
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => '',
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 0,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => 'POST',
            CURLOPT_POSTFIELDS => json_encode($data),
            CURLOPT_HTTPHEADER => array(
                'User-Agent: xxxx',
                'Content-Type: application/json',
            ),
        ));
        $response = curl_exec($curl);
        curl_close($curl);
        return json_decode($response, true);
    }

    public static function getQuota(string $symbol): array
    {
        return [];
    }
}